package com.smedi.ismedi.inmail.core.application.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.authority.starter.util.VerifyHelper;
import com.smedi.ismedi.cache.starter.util.RedisUtil;
import com.smedi.ismedi.file.dto.request.SignatureRequest;
import com.smedi.ismedi.file.dto.response.FileInfoResponse;
import com.smedi.ismedi.inmail.core.application.command.*;
import com.smedi.ismedi.inmail.core.application.convert.AppConverter;
import com.smedi.ismedi.inmail.core.application.service.AnnouncementApplicationService;
import com.smedi.ismedi.inmail.core.application.service.TaskApplicationService;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Attachment;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Person;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.announcement.Announcement;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.announcement.AttachmentKeyAndTime;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.announcement.Receiver;
import com.smedi.ismedi.inmail.core.domain.dto.AnnouncementQuery;
import com.smedi.ismedi.inmail.core.domain.dto.AttachmentQuery;
import com.smedi.ismedi.inmail.core.domain.dto.PersonQuery;
import com.smedi.ismedi.inmail.core.domain.dto.ReadRecord;
import com.smedi.ismedi.inmail.core.domain.repository.AttachmentRepository;
import com.smedi.ismedi.inmail.core.domain.repository.PersonRepository;
import com.smedi.ismedi.inmail.core.domain.service.AnnouncementDomainService;
import com.smedi.ismedi.inmail.core.infrastructure.constant.AnnouncementStatusEnum;
import com.smedi.ismedi.inmail.core.infrastructure.constant.InmailError;
import com.smedi.ismedi.inmail.core.infrastructure.util.DownloadFilesToZip;
import com.smedi.ismedi.inmail.core.port.adapter.persistence.model.AnnouncementReceiverRelationshipEntity;
import com.smedi.ismedi.inmail.core.port.adapter.persistence.mybatis.mapper.AnnouncementReceiverRelationshipMapper;
import com.smedi.ismedi.inmail.core.port.adapter.service.FileRemoteApi;
import com.smedi.ismedi.inmail.core.port.adapter.service.FileRemoteApiService;
import com.smedi.ismedi.inmail.core.port.adapter.service.impl.MessageRemoteServiceImpl;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.smedi.ismedi.inmail.core.infrastructure.constant.AnnouncementDealMethodEnum.NOT_PASS;
import static com.smedi.ismedi.inmail.core.infrastructure.constant.AnnouncementDealMethodEnum.PASS;
import static com.smedi.ismedi.inmail.core.infrastructure.constant.AnnouncementStatusEnum.*;
import static com.smedi.ismedi.inmail.core.infrastructure.constant.ConstantField.*;
import static com.smedi.ismedi.inmail.core.infrastructure.constant.ReadRecordStatusEnum.FINISHED;
import static com.smedi.ismedi.inmail.core.infrastructure.constant.ReadRecordStatusEnum.UPDATING;

/**
 * 通知公告应用服务实现类
 *
 * @author jiangqinxuan
 * @date 2021/07/26
 */
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class AnnouncementApplicationServiceImpl implements AnnouncementApplicationService {
    private final AnnouncementDomainService announcementDomainService;
    private final FileRemoteApiService fileRemoteApiService;
    private final PersonRepository personRepository;
    private final AuthorityUtil authorityUtil;
    private final AppConverter appConverter;
    private final TaskApplicationService taskApplicationService;
    private final MessageRemoteServiceImpl messageRemoteService;
    private final FileRemoteApi fileRemoteApi;
    private final AttachmentRepository attachmentRepository;
    private final AnnouncementReceiverRelationshipMapper announcementReceiverRelationshipMapper;
    private final RedisUtil redisUtil;
    private final ObjectMapper objectMapper;
    private final VerifyHelper verifyHelper;

    @Value("${fdfs.service.address.in}")
    private String FDFS_SERVICE_ADDRESS;


    @Override
    public Announcement createAnnouncement(AnnouncementCreateCommand announcementCreateCommand) {
        Announcement announcement = appConverter.announcementCreateCommandToAnnouncement(announcementCreateCommand);
        announcement.setPublisher(new Person(authorityUtil.getPersonId()));
        announcement.setCreateDateTime(LocalDateTime.now());
        announcement.getTask().setStatus(AnnouncementStatusEnum.A_TO_REVIEW.toString());

        Set<Long> personIds = new HashSet<>();
        personIds.add(announcementCreateCommand.getNextDealUserId());
        personIds.addAll(announcementCreateCommand.getReceiverIds());
        List<Person> people = personRepository.getPersonList(PersonQuery.builder().ids(new ArrayList<>(personIds)).build());
        Map<Long, Person> idPersonMap = new HashMap<>();
        for (Person person : people) {
            idPersonMap.put(person.getId(), person);
        }
        Person reviewer = idPersonMap.getOrDefault(announcementCreateCommand.getNextDealUserId(), new Person(announcementCreateCommand.getNextDealUserId()));

        // 过滤内部员工
        if (announcement.getInternal()) {
            announcement.getReceivers().clear();
            List<Long> receiverIds = announcementCreateCommand.getReceiverIds();
            for (Long receiverId : receiverIds) {
                Person receiver = idPersonMap.getOrDefault(receiverId, new Person(receiverId));
                if (null != receiver && receiver.getInternal()) {
                    announcement.getReceivers().add(Receiver.builder().id(receiver.getId()).build());
                }
            }
        }

        if (!verifyHelper.isAvailable(announcement.getReceivers())) {
            throw LogicException.raise(InmailError.RECEIVER_IS_EMPTY);
        }

        Announcement announcementSaved = announcementDomainService.saveAnnouncement(announcement);

        taskApplicationService.addTask(TaskRecordCommand.builder()
                .sourceFromId(announcementSaved.getId())
                .taskType("通知公告")
                .taskName("通知公告审批")
                .taskDescribe(announcement.getTitle())
                .dealPersonId(reviewer.getId())
                .dealPersonName(reviewer.getName())
                .taskStatus("进行中")
                .build());

        //创建通知公告，给审批人发短信通知
        messageRemoteService.sendMessage(MessageSendCommand.builder()
                .smsTemplateName("通知公告审批")
                .mobiles(new ArrayList<>(Collections.singletonList(reviewer.getMobile())))
                .parameters(new ArrayList<>(Collections.singletonList(reviewer.getName())))
                .build());

        return announcementSaved;
    }

    @Override
    public Announcement editAnnouncement(AnnouncementEditCommand announcementEditCommand) {
        redisUtil.del(ANNOUNCEMENT_CACHE_KEY + COLONS + announcementEditCommand.getId());

        Announcement announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementEditCommand.getId()).build());
        Announcement announcementEdited = appConverter.updateAnnouncementByAnnouncementEditCommand(announcement, announcementEditCommand);
        announcementEdited.getTask().setStatus(A_TO_REVIEW.toString());

        // 过滤内部员工
        if (announcement.getInternal()) {
            announcement.getReceivers().clear();
            List<Long> receiverIds = announcementEditCommand.getReceiverIds();
            List<Person> people = personRepository.getPersonList(PersonQuery.builder().ids(receiverIds).build());
            for (Person person : people) {
                if (person.getInternal()) {
                    announcement.getReceivers().add(Receiver.builder().id(person.getId()).build());
                }
            }
        }

        List<String> oldStatus = new ArrayList<>();
        oldStatus.add("进行中");

        Announcement announcementSaved = announcementDomainService.saveAnnouncement(announcementEdited);
        Announcement announcementQueried = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementSaved.getId()).build());

        taskApplicationService.updateTaskStatus(TaskRecordCommand.builder()
                .sourceFromId(announcement.getId())
                .taskType("通知公告")
                .taskName("通知公告退回")
                .dealPersonId(announcementQueried.getPublisher().getId())
                .dealPersonName(announcementQueried.getPublisher().getName())
                .oldStatus(oldStatus)
                .taskStatus("已完成")
                .build());

        taskApplicationService.addTask(TaskRecordCommand.builder()
                .sourceFromId(announcement.getId())
                .taskType("通知公告")
                .taskName("通知公告审批")
                .taskDescribe(announcement.getTitle())
                .dealPersonId(announcementQueried.getReviewer().getId())
                .dealPersonName(announcementQueried.getReviewer().getName())
                .taskStatus("进行中")
                .build());

        //创建通知公告，给审批人发短信通知
        String templateName = "通知公告审批";
        messageRemoteService.sendMessage(announcementQueried.getReviewer(), templateName);
        return announcementQueried;
    }

    @Override
    public Announcement reviewAnnouncement(AnnouncementReviewCommand announcementReviewCommand) {
        Announcement announcementReviewed;

        String reviewAnnouncementLockKey = "reviewAnnouncement" + COLONS + "announcementId" + COLONS + announcementReviewCommand.getId();

        if (redisUtil.incr(reviewAnnouncementLockKey, 1) != 1) {
            return null;
        }

        try {
            redisUtil.del(ANNOUNCEMENT_CACHE_KEY + COLONS + announcementReviewCommand.getId());

            Announcement announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementReviewCommand.getId()).build());

            if (!announcement.getTask().getStatus().equals(A_TO_REVIEW.name())) {
                return null;
            }

            List<String> oldStatus = new ArrayList<>();
            oldStatus.add("进行中");

            if (announcementReviewCommand.getMethod().equals(PASS.toString())) {
                announcement.getTask().setStatus(C_PUBLISHED.toString());
                announcement.setPublishDateTime(LocalDateTime.now());
            }
            if (announcementReviewCommand.getMethod().equals(NOT_PASS.toString())) {
                announcement.getTask().setStatus(B_BACK.toString());
            }

            announcement.setReviewDateTime(LocalDateTime.now());
            announcementReviewed = appConverter.updateAnnouncementByAnnouncementReviewCommand(announcement, announcementReviewCommand);
            announcementDomainService.saveAnnouncement(announcementReviewed);


            if (announcementReviewCommand.getMethod().equals(PASS.toString())) {
                taskApplicationService.updateTaskStatus(TaskRecordCommand.builder()
                        .sourceFromId(announcement.getId())
                        .taskType("通知公告")
                        .taskName("通知公告审批")
                        .dealPersonId(announcement.getReviewer().getId())
                        .dealPersonName(announcement.getReviewer().getName())
                        .oldStatus(oldStatus)
                        .taskStatus("已完成")
                        .build());

                //通知公告审批通过，给发布者发短信通知
                String templateName = "通知公告审批通过";
                messageRemoteService.sendMessage(announcement.getPublisher(), templateName);

                List<MessageSendCommand> messageSendCommands = new ArrayList<>();
                for (Receiver receiver : announcement.getReceivers()) {
                    messageSendCommands.add(MessageSendCommand.builder()
                            .smsTemplateName("通知公告接受人")
                            .mobiles(new ArrayList<>(Collections.singletonList(receiver.getMobile())))
                            .parameters(new ArrayList<>(Arrays.asList(receiver.getName(), announcement.getTitle())))
                            .build());
                }
                try {
                    messageRemoteService.sendMessage(messageSendCommands);
                } catch (Exception exception) {
                    log.error("短信發送失敗！:{}", exception.getMessage());
                }
            }
            if (announcementReviewCommand.getMethod().equals(NOT_PASS.toString())) {
                taskApplicationService.updateTaskStatus(TaskRecordCommand.builder()
                        .sourceFromId(announcement.getId())
                        .taskType("通知公告")
                        .taskName("通知公告审批")
                        .dealPersonId(announcement.getReviewer().getId())
                        .dealPersonName(announcement.getReviewer().getName())
                        .oldStatus(oldStatus)
                        .taskStatus("已完成")
                        .build());

                taskApplicationService.addTask(TaskRecordCommand.builder()
                        .sourceFromId(announcement.getId())
                        .taskType("通知公告")
                        .taskName("通知公告退回")
                        .taskDescribe(announcement.getTitle())
                        .dealPersonId(announcement.getPublisher().getId())
                        .dealPersonName(announcement.getPublisher().getName())
                        .taskStatus("进行中")
                        .build());

                //通知公告审批退回，给发布者发短信通知
                String templateName = "通知公告审批退回";
                messageRemoteService.sendMessage(announcement.getPublisher(), templateName);
            }
        } finally {
            redisUtil.set(reviewAnnouncementLockKey, 0, TOKEN_EFFECTIVE_TIME);
        }

        return announcementReviewed;
    }

    @Override
    public Announcement disableAnnouncement(AnnouncementDisableCommand announcementDisableCommand) {
        redisUtil.del(ANNOUNCEMENT_CACHE_KEY + COLONS + announcementDisableCommand.getId());
        Announcement announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementDisableCommand.getId()).build());
        announcement.getTask().setStatus(D_NOT_AVAILABLE.toString());
        return announcementDomainService.saveAnnouncement(announcement);
    }

    @Override
    public void removeAnnouncement(AnnouncementRemoveCommand announcementRemoveCommand) {
        redisUtil.del(ANNOUNCEMENT_CACHE_KEY + COLONS + announcementRemoveCommand.getId());
        AnnouncementQuery announcementQuery = appConverter.announcementRemoveCommandToAnnouncementQuery(announcementRemoveCommand);
        announcementDomainService.removeAnnouncement(announcementQuery);
    }

    @Override
    public Announcement readAnnouncement(AnnouncementReadCommand announcementReadCommand) {
        Announcement announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementReadCommand.getId()).build());
        LambdaQueryWrapper<AnnouncementReceiverRelationshipEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AnnouncementReceiverRelationshipEntity::getReceiverId, authorityUtil.getPersonId());
        lambdaQueryWrapper.eq(AnnouncementReceiverRelationshipEntity::getAnnouncementId, announcementReadCommand.getId());
        AnnouncementReceiverRelationshipEntity announcementReceiverRelationshipEntity = announcementReceiverRelationshipMapper.selectOne(lambdaQueryWrapper);
        if (null == announcementReceiverRelationshipEntity) {
            return announcement;
        }
        if (null != announcementReceiverRelationshipEntity.getReadTime()) {
            return announcement;
        }
        announcementReceiverRelationshipEntity.setReadTime(LocalDateTime.now());
        announcementReceiverRelationshipMapper.updateById(announcementReceiverRelationshipEntity);
        announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(announcementReadCommand.getId()).build());
        return announcement;
    }

    @Override
    public byte[] downloadFilesToZip(List<String> attachmentKeyList) {
        // 获取附件信息
        List<FileInfoResponse> fileInfoResponseList = fileRemoteApiService.getFileInfoListByKeyList(attachmentKeyList);

        // 下载文件压缩成压缩包
        return DownloadFilesToZip.downloadFilesToZip(fileInfoResponseList, FDFS_SERVICE_ADDRESS);
    }

    @Override
    public FileInfoResponse postDownloadFilesSetNameToZip(List<AttachmentKeyAndTime> attachmentKeyAndTimeList) throws IOException {
        List<String> attachmentKeyList = new ArrayList<>();
        Map<String,LocalDateTime> attachmentKeyAndTimeMap = new HashMap<>();
        attachmentKeyAndTimeList.forEach(it -> {
            attachmentKeyAndTimeMap.put(it.getAttachmentKey(),it.getPublishDatetime());
            attachmentKeyList.add(it.getAttachmentKey());
        });
        List<FileInfoResponse> fileInfoResponseList = fileRemoteApiService.getFileInfoListByKeyList(attachmentKeyList);
        if(CollectionUtils.isNotEmpty(fileInfoResponseList)){
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            fileInfoResponseList.stream().forEach(it->{
                if(attachmentKeyAndTimeMap.containsKey(it.getSignKey())){
                    it.setName(attachmentKeyAndTimeMap.get(it.getSignKey()).format(dateTimeFormatter)+"-"+it.getName());
                }
            });
        }
        List<LocalDateTime> timeList = attachmentKeyAndTimeList.stream().map(it->it.getPublishDatetime()).distinct().sorted().collect(Collectors.toList());
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        File file = DownloadFilesToZip.downloadFilesToZipFile(fileInfoResponseList, FDFS_SERVICE_ADDRESS);
        FileInfoResponse fileInfoResponse = fileRemoteApiService.uploadFileGetResponse(file);
        Files.deleteIfExists(Paths.get(file.getAbsolutePath()));
        fileInfoResponse.setName(timeList.get(0).format(dateTimeFormatter)+"-"+timeList.get(timeList.size()-1).format(dateTimeFormatter)+"-通知公告附件");
        return fileInfoResponse;
    }

    @Override
    public void updateReadRecord(AnnouncementReadRecordCommand announcementReadRecordCommand) throws IOException {
        String updateReadRecordLockKey = "updateReadRecord" + COLONS + "announcementId" + COLONS + announcementReadRecordCommand.getId();

        if (redisUtil.incr(updateReadRecordLockKey, 1) != 1) {
            return;
        }

        try {
            AnnouncementQuery announcementQuery = appConverter.announcementReadRecordCommandToAnnouncementQuery(announcementReadRecordCommand);
            Announcement announcement = announcementDomainService.getAnnouncementOne(announcementQuery);
            List<String> signaturePDFs = new ArrayList<>();

            // 收集全部维度的统计
            List<Announcement.Statistics> statisticsInInstitution = announcement.getStatisticsInInstitution();
            List<Announcement.Statistics> allStatistics = new ArrayList<>(statisticsInInstitution);
            List<Announcement.Statistics> statisticsInOrganization = announcement.getStatisticsInOrganization();
            allStatistics.addAll(statisticsInOrganization);
            List<Announcement.StatisticsInProject> statisticsInProject = announcement.getStatisticsInProject();
            for (Announcement.StatisticsInProject statistics : statisticsInProject) {
                allStatistics.addAll(statistics.getProjectStatistics());
            }

            Map<String, Announcement.Statistics> signKeyStatisticsMap = new HashMap<>();
            for (Announcement.Statistics statistics : allStatistics) {
                String signaturePDF = getSignaturePDF(statistics, announcement);
                signaturePDFs.add(signaturePDF);
                signKeyStatisticsMap.put(signaturePDF, statistics);
            }

            List<Attachment> attachments = attachmentRepository.getAttachmentList(AttachmentQuery.builder().signKeys(signaturePDFs).build());

            String readRecordLogString = "";
            ReadRecord readRecord = ReadRecord.builder().announcementId(announcementReadRecordCommand.getId()).status(UPDATING.name()).totalNum(attachments.size()).finishedNum(0).build();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            InputStream inputStream;
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
                int finishNum = 0;
                for (Attachment attachment : attachments) {
                    readRecord.setFinishedNum(finishNum);
                    // 更新缓存
                    try {
                        readRecordLogString = objectMapper.writeValueAsString(readRecord);
                    } catch (Exception exception) {
                        log.error("json转换错误");
                    }
                    redisUtil.set("readRecord" + COLONS + announcementReadRecordCommand.getId(), readRecordLogString, 60 * 60 * 24 * 30);
                    inputStream = new URL(attachment.getUrlIn()).openStream();
                    Announcement.Statistics statistics = signKeyStatisticsMap.getOrDefault(attachment.getSignKey(), new Announcement.Statistics());
                    ZipEntry entry = new ZipEntry(statistics.getName() + ".pdf");
                    zipOutputStream.putNextEntry(entry);
                    finishNum = finishNum + 1;
                    int len;
                    byte[] buffer = new byte[1024];
                    while ((len = inputStream.read(buffer)) != -1) {
                        zipOutputStream.write(buffer, 0, len);
                    }
                    zipOutputStream.closeEntry();
                    inputStream.close();
                }
            }

            File outputFile = File.createTempFile(IdUtil.simpleUUID(), ".zip");
            try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile.getPath())) {
                fileOutputStream.write(byteArrayOutputStream.toByteArray());
                String zipKey = fileRemoteApi.uploadFile(outputFile);
                FileInfoResponse file = fileRemoteApi.getFileOne(AttachmentQuery.builder().signKey(zipKey).build());
                readRecord.setStatus(FINISHED.name());
                readRecord.setUpdatedTime(LocalDateTime.now());
                readRecord.setUrl(file.getUrlOut());
                try {
                    readRecordLogString = objectMapper.writeValueAsString(readRecord);
                } catch (Exception exception) {
                    log.error("json转换错误");
                }
                redisUtil.set("readRecord" + COLONS + announcementReadRecordCommand.getId(), readRecordLogString, 60 * 60 * 24 * 30);
            } catch (Exception exception) {
                log.error("文件上传失败");
            } finally {
                FileUtils.delete(outputFile);
            }
        } finally {
            redisUtil.set(updateReadRecordLockKey, 0, TOKEN_EFFECTIVE_TIME);
        }
    }

    @Override
    public Attachment getReadRecordOne(ReadRecordOneQueryCommand readRecordOneQueryCommand) throws IOException {
        String signaturePDF = "";
        Announcement announcement = announcementDomainService.getAnnouncementOne(AnnouncementQuery.builder().id(readRecordOneQueryCommand.getAnnouncementId()).build());
        // 收集统计信息
        List<Announcement.Statistics> statistics = new ArrayList<>(announcement.getStatisticsInInstitutionAndOrganization());
        for (Announcement.StatisticsInProject statisticsInProject : announcement.getStatisticsInProject()) {
            statistics.addAll(statisticsInProject.getProjectStatistics());
        }

        for (Announcement.Statistics statistic : statistics) {
            if (statistic.getSourceFromId().equals(readRecordOneQueryCommand.getSourceFromId()) && statistic.getSourceFromType().equals(readRecordOneQueryCommand.getSourceFromType())) {
                signaturePDF = getSignaturePDF(statistic, announcement);
            }
        }

        if (null == signaturePDF) {
            return null;
        }

        return attachmentRepository.getAttachmentOne(AttachmentQuery.builder().signKey(signaturePDF).build());
    }

    @Override
    public ReadRecord getAllReadRecordZip(ReadRecordAllZipQueryCommand readRecordAllZipQueryCommand) {
        ReadRecord readRecord = null;
        Object readRecordObject = redisUtil.get("readRecord" + COLONS + readRecordAllZipQueryCommand.getAnnouncementId());
        if (null != readRecordObject) {
            try {
                readRecord = objectMapper.readValue(String.valueOf(readRecordObject), ReadRecord.class);
            } catch (Exception exception) {
                log.error("json转换错误");
            }
        }
        return readRecord;
    }

    @Override
    @SneakyThrows
    public String exportAnnouncement(List<Announcement> announcements) {
        String fileKey = "";
        ClassPathResource classPathResource = new ClassPathResource("fileTemplate/announcement.xlsx");
        XSSFWorkbook workBook;
        try (InputStream inputStream = classPathResource.getInputStream()) {
            workBook = new XSSFWorkbook(inputStream);
        }
        XSSFSheet buildingSheet = workBook.cloneSheet(0, "项目统计");
        XSSFCellStyle cellStyle = workBook.createCellStyle();
        //启动单元格内换行
        cellStyle.setWrapText(true);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        int i = 1;
        for (Announcement announcement : announcements) {
            i++;
            XSSFRow rowAdd = buildingSheet.createRow(i);
            rowAdd.setHeight((short) 600);
            for (int j = 0; j < 4; j++) {
                rowAdd.createCell(j);
                rowAdd.getCell(j).setCellStyle(cellStyle);
            }
            rowAdd.getCell(0).setCellValue(i - 1);
            rowAdd.getCell(1).setCellValue(null == announcement.getPublishDateTime() ? "-" : announcement.getPublishDateTime().toString().replaceAll("T", " "));
            rowAdd.getCell(2).setCellValue(String.valueOf(announcement.getTitle()));
            rowAdd.getCell(3).setCellValue(null == announcement.getPublisher() ? "-" : String.valueOf(announcement.getPublisher().getName()));
        }

        workBook.removeSheetAt(0);

        final File outputFile = File.createTempFile(IdUtil.simpleUUID(), ".xlsx");
        try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
            workBook.write(outputStream);
            fileKey = fileRemoteApi.uploadFile(outputFile);
        } catch (Exception e) {
            log.info(e.getMessage());
        } finally {
            Files.deleteIfExists(Paths.get(outputFile.getAbsolutePath()));
        }

        return fileKey;
    }

    private String getSignaturePDF(Announcement.Statistics statistics, Announcement announcement) throws
            IOException {
        Map<String, Object> stringObjectMap = new HashMap<>();
        stringObjectMap.put("inmailDate", announcement.getPublishDateTime().toLocalDate().toString().replace("T", " "));
        stringObjectMap.put("inmailName", announcement.getTitle());
        String recordPdf = "";

        List<SignatureRequest> signatureRequests = new ArrayList<>();
        List<ReceiverRecord> receiverRecords = new ArrayList<>();
        List<Receiver> receivers = statistics.getReceivers();
        for (int i = receivers.size() - 1; i >= 0; i--) {
            Receiver receiver = receivers.get(i);
            ReceiverRecord receiverRecord = new ReceiverRecord();
            receiverRecord.setName(receiver.getName());
            if (receiver.getIsRead()) {
                if (ObjectUtils.isNotEmpty(receivers.get(i).getEmployeeNum())) {
                    receiverRecord.setSign(receiver.getName() + "_true");
                    SignatureRequest signatureRequest = new SignatureRequest();
                    signatureRequest.setSignLocation(receivers.get(i).getName() + "_true");
                    signatureRequest.setWorkerId(Long.valueOf(receivers.get(i).getEmployeeNum()));
                    signatureRequests.add(signatureRequest);
                }
                LocalDateTime readTime = receiver.getReadTime();
                receiverRecord.setSignDate(LocalDateTime.of(readTime.toLocalDate(), LocalTime.of(readTime.getHour(), readTime.getMinute(), readTime.getSecond())).toString().replace("T", " "));
            }
            receiverRecords.add(receiverRecord);
        }
        stringObjectMap.put("receiverRecords", receiverRecords);
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure config = Configure.builder().bind("receiverRecords", policy).build();
        Resource resource = new ClassPathResource("fileTemplate/fileRecord.docx");
        InputStream inputStream = resource.getInputStream();
        XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render(stringObjectMap);

        final File outputFile = File.createTempFile(IdUtil.simpleUUID(), ".docx");
        try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
            template.write(outputStream);

            String recordDoc = fileRemoteApi.uploadFile(outputFile);
            recordPdf = fileRemoteApi.convertToPdf(recordDoc);
            if (CollectionUtils.isNotEmpty(signatureRequests)) {
                for (SignatureRequest signatureRequest : signatureRequests) {
                    signatureRequest.setFileKey(recordPdf);
                }
                recordPdf = fileRemoteApi.postSignatures(signatureRequests);
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        } finally {
            Files.deleteIfExists(Paths.get(outputFile.getAbsolutePath()));
        }

        return recordPdf;
    }

    @NoArgsConstructor
    @Data
    public static class ReceiverRecord {
        private String name;
        private String sign;
        private String signDate;
    }
}
